package org.oschina.api.user.active.dao;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.oschina.Constants;
import org.oschina.api.BaseDAO;
import org.oschina.api.user.active.model.UserActive;
import org.oschina.api.user.active.model.UserActivePushBean;
import org.oschina.api.user.active.vo.UserActiveTypeVo;
import org.oschina.api.user.active.vo.UserActiveVo;
import org.oschina.api.user.user.dao.UserDAO;
import org.oschina.api.user.user.vo.UserVo;
import org.oschina.helper.cache.ICachePipeline;
import org.oschina.helper.query.IQueryCacheCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class UserActiveDAO extends BaseDAO {
	
	@Autowired
	private UserDAO userDAO;
	@Autowired
	private UserActiveTypeDAO userActiveTypeDAO;
	
	private final String findVoByAuthor="SELECT usa.id,us.id as 'author.id',us.username as 'author.username',us.headphoto as 'author.headphoto',usa.major,usa.title,usa.content,usa.create_time,usat.id as 'type.id',usat.message as 'type.message',usat.url as 'type.url'" +
			" FROM "+Constants.DB_USER+" us,"+Constants.DB_USER_ACTIVE+" usa,"+Constants.DB_USER_ACTIVE_TYPE+" usat" +
			" WHERE usa.author_id=? AND us.id=usa.author_id AND usa.type=usat.id ORDER BY usa.create_time DESC LIMIT ?,?";
	/**
	 * 根据作者返回
	 * @param author
	 * @param first
	 * @param max
	 * @return
	 */
	public List<UserActiveVo> findVoByAuthor(final int author,int first,int max)
	{
		List<UserActiveVo> result=null;
		if(isNeedCache(author))
		{
			result=getQueryHelper().query_cache(_findVoByAuthorCache(author), Constants.MAX_CACHE_USER_ACITVE_BY_AUTHOR, first, max, UserActiveVo.class, new IQueryCacheCallback() 
			{
				@Override
				public List get(int first, int max)
				{
					return _findVoByAuthor(author,first,max);
				}
			});
		}
		else
			result=_findVoByAuthor(author,first,max);
		
		return handleTypeData(result);
	}
	private List<UserActiveVo> _findVoByAuthor(int author,int first,int max)
	{
		return getQueryHelper().query(findVoByAuthor, new Object[]{author,first,max}, UserActiveVo.class);
	}
	private String _findVoByAuthorCache(int author)
	{
		return this.getKey(Constants.CACHE_USER_ACTIVE_BY_AUTHOR, author);
	}
	private void _pushByAuthor(int author,int active)
	{
		getCacheHelper().lpush(_findVoByAuthorCache(author), active, Constants.TIMEOUT_USER_ACTIVE);
	}
	
	/**
	 * 根据作者返回数量
	 * @param author
	 * @return
	 */
	public int getCountByAuthor(int author)
	{
		if(isNeedCache(author))
		{
			String key=_getCountByAuthorCache(author);
			Integer result=(Integer) getCacheHelper().get(key, Integer.class);
			if(result==null)
			{
				result=_getCountByAuthor(author);
				getCacheHelper().set(key, result, Constants.TIMEOUT_USER_ACTIVE);
			}
			return result;
		}
		return _getCountByAuthor(author);
	}
	private int _getCountByAuthor(int author)
	{
		return (int) getQueryHelper().queryDataSum(new String[]{"author_id=?"}, new Object[]{author},UserActiveVo.class);
	}
	private String _getCountByAuthorCache(int author)
	{
		return this.getKey(Constants.CACHE_USER_ACTIVE_BY_AUTHOR_COUNT, author);
	}
	private void _updateCountByAuthor(int author,int count)
	{
		getCacheHelper().incr(_getCountByAuthorCache(author), count);
	}
	
	private final String findVoByAuthorAndFollow="SELECT usa.id,us.id as 'author.id',us.username as 'author.username',us.headphoto as 'author.headphoto',usa.major,usa.title,usa.content,usa.create_time,usat.id as 'type.id',usat.message as 'type.message',usat.url as 'type.url'" +
		" FROM "+Constants.DB_USER+" us,"+Constants.DB_USER_ACTIVE+" usa,"+Constants.DB_USER_ACTIVE_TYPE+" usat" +
		" WHERE (us.id IN (SELECT usf.target FROM "+Constants.DB_USER_FOLLOW+" usf WHERE usf.source=?) OR us.id=?) AND usa.author_id=us.id AND usa.type=usat.id ORDER BY usa.create_time DESC LIMIT ?,?";
	/**
	 * 根据作者和关注返回
	 * @param author
	 * @param first
	 * @param max
	 * @return
	 */
	public List<UserActiveVo> findVoByAuthorAndFollow(final int author,int first,int max)
	{
		return handleTypeData(getQueryHelper().query_cache(_findVoByAuthorAndFollow(author), Constants.MAX_CACHE_USER_ACTIVE_BY_AUTHOR_AND_FOLLOW, first, max, UserActiveVo.class, new IQueryCacheCallback() 
		{
			@Override
			public List get(int first, int max)
			{
				return _findVoByAuthorAndFollow(author,first,max);
			}
		}));
	}
	private List<UserActiveVo> _findVoByAuthorAndFollow(int author,int first,int max)
	{
		return getQueryHelper().query(findVoByAuthorAndFollow, new Object[]{author,author,first,max}, UserActiveVo.class);
	}
	private String _findVoByAuthorAndFollow(int author)
	{
		return this.getKey(Constants.CACHE_USER_ACTIVE_BY_AUTHOR_AND_FOLLOW, author);
	}
	public void _pushByAuthorAndFollow(int author,int active)
	{
		getCacheHelper().lpush(_findVoByAuthorAndFollow(author), active, Constants.TIMEOUT_USER_ACTIVE);
	}
	
	private List<UserActiveVo> handleTypeData(List<UserActiveVo> list)
	{
		if(list!=null && !list.isEmpty())
		{
			for(UserActiveVo userActive:list)
				userActive.getType().setUrl(StringUtils.replaceEach(userActive.getType().getUrl(), new String[]{"{major}"}, new String[]{userActive.getMajor().toString()}));
		}
		return list;
	}
	
	private final String getCountByAuthorAndFollow="SELECT COUNT(*)" +
		" FROM "+Constants.DB_USER+" us LEFT JOIN "+Constants.DB_USER_FOLLOW+" usf ON usf.source=us.id,"+Constants.DB_USER_ACTIVE+" usa" +
		" WHERE us.id=? AND (usa.author_id=us.id or usa.author_id=usf.target)";
	/**
	 * 根据作者和关注返回数量
	 * @param author
	 * @return
	 */
	public int getCountByAuthorAndFollow(int author)
	{
		String key=_getCountByAuthorAndFollowCache(author);
		Integer result=(Integer) getCacheHelper().get(key, Integer.class);
		if(result==null)
		{
			result=_getCountByAuthorAndFollow(author);
			getCacheHelper().set(key, result, Constants.TIMEOUT_USER_ACTIVE);
		}
		return result;
	}
	private int _getCountByAuthorAndFollow(int author)
	{
		return (Integer) getQueryHelper().queryForObject(getCountByAuthorAndFollow, new Object[]{author}, Integer.class);
	}
	private String _getCountByAuthorAndFollowCache(int author)
	{
		return this.getKey(Constants.CACHE_USER_ACTIVE_BY_AUTHOR_AND_FOLLOW_COUNT, author);
	}
	public void _updateCountByAuthorAndFollow(int author,int count)
	{
		getCacheHelper().incr(_getCountByAuthorAndFollowCache(author), count);
	}
	
	/**
	 * 是否需要缓存
	 * @param author
	 * @return
	 */
	private boolean isNeedCache(int author)
	{
		return userDAO.isInCache(author);
	}
	
	/**
	 * 清理缓存
	 * @param author
	 */
	public void removeCache(int author)
	{
		ICachePipeline pipeline=getCacheHelper().getPipeline();
		pipeline.del(_findVoByAuthorAndFollow(author));
		pipeline.del(_getCountByAuthorAndFollowCache(author));
		pipeline.sync();
	}
	
	/**
	 * 创建
	 * @param userActive
	 * @return
	 */
	public UserActive create(UserActive userActive)
	{
		batchUpdate_queue("INSERT "+Constants.DB_USER_ACTIVE+"(id,author_id,major,title,content,type,create_time) VALUES(?,?,?,?,?,?,?)", 
				new Object[]{userActive.getId(),userActive.getAuthor().getId(),userActive.getMajor(),userActive.getTitle(),userActive.getContent(),userActive.getType(),userActive.getCreate_time()});
		
		_push(userActive);
		return userActive;
	}
	
	private void _push(UserActive userActive)
	{
		if(!_putCache(userActive))
			return;
		
		_pushByAuthor(userActive.getAuthor().getId(), userActive.getId());
		_updateCountByAuthor(userActive.getAuthor().getId(), 1);
		getMessageQueueHelper().send(Constants.QUEUE_USER_ACTIVE_PUSH, new UserActivePushBean(userActive.getAuthor().getId(),userActive.getId()));
	}
	
	private boolean _putCache(UserActive userActive)
	{
		UserActiveTypeVo type=userActiveTypeDAO.findVoById(userActive.getType());
		type.setName(null);
		
		UserVo author=new UserVo();
		author.setId(userActive.getAuthor().getId());
		author.setUsername(userActive.getAuthor().getUsername());
		author.setHeadphoto(userActive.getAuthor().getHeadphoto());
		
		UserActiveVo userActiveVo=new UserActiveVo();
		userActiveVo.setId(userActive.getId());
		userActiveVo.setContent(userActive.getContent());
		userActiveVo.setCreate_time(userActive.getCreate_time());
		userActiveVo.setMajor(userActive.getMajor());
		userActiveVo.setTitle(userActive.getTitle());
		
		userActiveVo.setAuthor(author);
		userActiveVo.setType(type);
		
		getCacheHelper().hset(_getIdKey(userActive.getId()), userActiveVo, UserActiveVo.class, Constants.TIMEOUT_USER_ACTIVE);
		return true;
	}
	
	private String _getIdKey(Object id)
	{
		return this.getKey(Constants.CACHE_USER_ACTIVE, id);
	}
}